# 
#   posix.rb
# 
#   Copyright (c) 2010-2011 Masoom Shaikh<masoomshaikh@users.sourceforge.net>
#   All rights reserved.
# 
#   Redistribution and use in source and binary forms, with or without
#   modification, are permitted provided that the following conditions
#   are met:
#   1. Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#   2. Redistributions in binary form must reproduce the above copyright
#      notice, this list of conditions and the following disclaimer in the
#      documentation and/or other materials provided with the distribution.
# 
#   THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
#   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#   ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
#   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
#   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
#   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
#   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
#   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
#   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#   SUCH DAMAGE.

require 'nokogiri'

class Configuration
  def initialize( doc)
    @doc = doc
  end

  def name
    @doc.attr('Name')
  end

  def conf_name
    self.name.split('|')[0]
  end

  def platform
    self.name.split('|')[1]
  end

  def output_directory
    @doc.attr('OutputDirectory')
  end

  def intermediate_directory
    @doc.attr('IntermediateDirectory')
  end

  def preprocessor_directives
    ret = nil
    @doc.xpath('./Tool').each do |elem|
      if elem.attr('Name') == 'VCCLCompilerTool'
        ret = elem.attr('PreprocessorDefinitions').split(';')
        break
      end
    end
    return ret
  end

  def preprocessor_directives=(directives)
    raise 'arg need as array' if not directives.kind_of? Array
    ret = nil
    @doc.xpath('./Tool').each do |elem|
      if elem.attr('Name') == 'VCCLCompilerTool'
        ret = elem.setAttribute('PreprocessorDefinitions', directives.join(';'))
        break
      end
    end
    return ret
  end

  def include_directories
    ret = nil
    @doc.xpath('./Tool').each do |elem|
      if elem.attr('Name') == 'VCCLCompilerTool'
        ret = elem.attr('AdditionalIncludeDirectories').split(';')
        break
      end
    end
    return ret
  end

  def include_directories=(dirs)
    raise 'arg need as array' if not dir.kind_of? Array
    ret = nil
    @doc.xpath('./Tool').each do |elem|
      if elem.attr('Name') == 'VCCLCompilerTool'
        ret = elem.setAttribute('AdditionalIncludeDirectories', dirs.join(';'))
        break
      end
    end
    return ret
  end

  def lib_directories
    ret = nil
    @doc.xpath('./Tool').each do |elem|
      if elem.attr('Name') == 'VCLinkerTool'
        ret = elem.attr('AdditionalLibraryDirectories').split(';')
        break
      end
    end
    return ret
  end

  def lib_directories=(dirs)
    raise 'arg need as array' if not dirs.kind_of? Array
    @doc.xpath('./Tool').each do |elem|
      if elem.attr('Name') == 'VCLinkerTool'
        elem.setAttribute('AdditionalLibraryDirectories', dirs.join(';'))
      end
    end
  end

  def lib_dependencies
    ret = nil
    @doc.xpath('./Tool').each do |elem|
      if elem.attr('Name') == 'VCLinkerTool'
        ret = elem.attr('AdditionalDependencies').split(' ')
        break
      end
    end
    return ret
  end

  def lib_dependencies=(depends)
    raise 'arg need as array' if not depends.kind_of? Array
    ret = nil
    @doc.xpath('./Tool').each do |elem|
      if elem.attr('Name') == 'VCLinkerTool'
        ret = elem.setAttribute('AdditionalDependencies', depends.join(' '))
        break
      end
    end
    return ret
  end
end

class Filter
  def initialize( doc)
    @doc = doc
  end

  def name
    @doc.attr('Name')
  end

  def files
    files = []
    @doc.xpath('./File').each do |file|
      files << file.attr('RelativePath')
    end
    files
  end
end

class VCProj
  def initialize(fname)
    @fname = fname
    @doc = Nokogiri::XML( File.new( @fname))
  end

  def name
    @doc.xpath('/VisualStudioProject').attr('Name').value
  end

  def save(fname = @fname)
    @doc.save(fname)
  end

  def files
    files = []
    res = @doc.xpath('/VisualStudioProject/Files/File')
    res.each do |file| files << file.attr('RelativePath') end
    files
  end

  def filters
    res = @doc.xpath('/VisualStudioProject/Files/Filter')
    ret = []
    res.each do |filter| ret << Filter.new( filter) end
    ret
  end

  def all_files
    ret = []
    filters.each do |filter|
      ret << filter.files
    end
    ret << self.files
    ret.flatten
  end

  def configurations
    res = @doc.xpath('/VisualStudioProject/Configurations/Configuration')
    ret = []
    res.each do |elem| ret << Configuration.new(elem); end
    return ret
  end

  def get_configuration( conf_name, platform)
    self.configurations.each do |cnf|
      if cnf.platform == platform and cnf.conf_name == conf_name
        return cnf
      end
    end
    raise StandardError, "no such configuration \nplatform=#{platform}, configuration=#{conf_name}"
  end
end
